package com.sparrow.source.third;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Maps;
import com.sparrow.source.common.CommonConstant;
import com.sparrow.source.common.dto.UnvDeviceInfo;
import com.sparrow.source.common.dto.UnvPeopleLibraries;
import com.sparrow.source.common.dto.UnvPerson;
import com.sparrow.source.common.dto.UnvPersonInfo;
import com.sparrow.source.common.dto.UnvPersonItem;
import com.sparrow.source.common.dto.convert.IasPersonConvert;
import com.sparrow.source.common.utils.ImageUtils;
import com.sparrow.source.common.utils.RedisUtils;
import com.sparrow.source.persistense.IasDeviceUser;
import com.sparrow.source.persistense.IasFace;
import com.sparrow.source.persistense.IasFaceSyncRes;
import com.sparrow.source.persistense.IasPerson;
import com.sparrow.source.persistense.IasUser;
import com.sparrow.source.persistense.UnvDevice;
import com.sparrow.source.service.IIasFaceService;
import com.sparrow.source.service.IIasFaceSyncResService;
import com.sparrow.source.service.IIasPersonService;
import com.sparrow.source.service.IIasUserService;
import com.sparrow.source.service.IUnvDeviceService;
import com.sparrow.source.service.IasDeviceUserService;
import com.sparrow.source.third.enums.UnvRequestURI;
import com.sparrow.source.third.util.RestTemplateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 宇视接口
 *
 * @author bryceyung
 * @since 2024/11/18
 */
@Component
@Slf4j
public class UnvClient {

    @Autowired
    private IUnvDeviceService unvDeviceService;

    @Autowired
    private IIasFaceService faceService;

    @Autowired
    private IIasFaceSyncResService faceSyncResService;

    @Autowired
    private IIasUserService userService;

    @Autowired
    private RestTemplateUtils restTemplateUtils;

    @Autowired
    private IasPersonConvert personConvert;

    @Autowired
    private IasDeviceUserService deviceUserService;

    @Autowired
    private ImageUtils imageUtils;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private RedisUtils redisUtils;

    private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

    /**
     * 获取人员库
     *
     * @param deviceId
     * @return
     */
    public UnvPeopleLibraries getPeopleLibraries(Integer deviceId) {
        UnvDevice device = unvDeviceService.getById(deviceId);
        if (device == null) {
            log.error("数据库未查询到对应设备数据 id:{}", deviceId);
            return null;
        }
        String url = "http://" + device.getIp();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "*/*");
        headers.setConnection("keep-alive");
        ResponseEntity<String> responseEntity = restTemplateUtils.get(url + UnvRequestURI.PEOPLE_LIBRARIES.getUri(), headers, String.class);
        JSONObject response = (JSONObject) JSONObject.parseObject(responseEntity.getBody()).get("Response");
        UnvPeopleLibraries result = JSONObject.parseObject(String.valueOf(response.get("Data")), UnvPeopleLibraries.class);
        return result;
    }

    /**
     * 获取设备信息
     *
     * @param deviceId
     * @return
     */
    public UnvDeviceInfo getDeviceInfo(Integer deviceId) {
        UnvDevice device = unvDeviceService.getById(deviceId);
        if (device == null) {
            log.error("数据库未查询到对应设备数据 id:{}", deviceId);
            return null;
        }
        String url = "http://" + device.getIp() + UnvRequestURI.SYSTEM_DEVICE_INFO.getUri();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "*/*");
        headers.setConnection("keep-alive");

        ResponseEntity<String> responseEntity = restTemplateUtils.get(url, headers, String.class);
        JSONObject response = (JSONObject) JSONObject.parseObject(responseEntity.getBody()).get("Response");
        UnvDeviceInfo result = JSONObject.parseObject(String.valueOf(response.get("Data")), UnvDeviceInfo.class);
        //同步获取 在设备上添加的人脸信息
        threadPoolTaskExecutor.execute(() -> {
            log.info("[getAllPeopleInfo] start >>>");
            getAllPeopleInfo(deviceId);
        });
        return result;
    }

    /**
     * 查询设备上人员信息
     *
     * @param deviceId
     * @return
     */
    public UnvPersonInfo getPeopleInfo(Integer deviceId, Integer offset) {
        UnvDevice device = unvDeviceService.getById(deviceId);
        if (device == null) {
            log.error("数据库未查询到对应设备数据 id:{}", deviceId);
            return null;
        }
        String url = "http://" + device.getIp() + UnvRequestURI.PEOPLE_LIBRARIES_INFO.getUri() + "3/People/Info";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "*/*");
        headers.setConnection("keep-alive");
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

        Map<String, Object> requestMap = Maps.newLinkedHashMap();
        requestMap.put("Num", 0);
        //        requestMap.put("QueryInfos", Lists.newArrayList());
        requestMap.put("Limit", 6);
        requestMap.put("Offset", offset);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestMap, headers);
        ResponseEntity<String> responseEntity = restTemplateUtils.post(url, request, String.class);
        JSONObject response = (JSONObject) JSONObject.parseObject(responseEntity.getBody()).get("Response");
        UnvPersonInfo personInfo = JSONObject.parseObject(JSONObject.toJSONString(response.get("Data")), UnvPersonInfo.class);
        //        List<IasPerson> personList = personConvert.unvPersonItemConvert(personInfo.getPersonList().get(0));
        return personInfo;
    }

    /**
     * UNV 限制一次只能获取6个人员信息，要获取所有人员需多次请求
     *
     * @param deviceId
     * @return
     */
    public Boolean getAllPeopleInfo(Integer deviceId) {
        List<UnvPersonItem> resultList = Lists.newArrayList();
        int initOffset = 0;
        UnvPersonInfo person = getPeopleInfo(deviceId, initOffset);
        if (person == null) {
            return false;
        }
        if (person.getPersonList().size() > 0) {
            resultList.addAll(person.getPersonList().get(0).getPersonInfoList());
        }
        double totalPage = Math.ceil((double) person.getTotal() / 6);
        for (int page = 2; page <= totalPage; page++) {
            initOffset += 6;
            UnvPersonInfo personInfo = getPeopleInfo(deviceId, initOffset);
            if (personInfo.getPersonList().size() > 0) {
                resultList.addAll(personInfo.getPersonList().get(0).getPersonInfoList());
            }
        }
        List<IasDeviceUser> deviceUsers = personConvert.unvPersonItemConvertIasUser(deviceId, resultList);
        return deviceUserService.batchCrdData(deviceId, deviceUsers);
    }

    /**
     * 设备要求单次请求最多包含6个人员
     *
     * @param deviceId
     * @param userList
     * @return
     */
    public UnvPerson addPersonInfo(Integer deviceId, List<IasUser> userList) {
        //        if (userList.size() > 6) {
        //            log.info("======== 添加人员信息失败：一次最多保存6个人员信息 ========");
        //            return null;
        //        }
        Map<String, Object> requestMap = new LinkedHashMap<>();
        requestMap.put("Num", userList.size());
        //同步记录生成
        Map<Integer, Integer> userFaceIdMap = Maps.newConcurrentMap();
        //组装personInfo
        List<Map> personInfoList = new ArrayList<>();
        userList.forEach(user -> {
            Map<String, Object> personInfoMap = new LinkedHashMap<>();
            personInfoMap.put("PersonID", user.getUid() == null ? user.getPersonId() : user.getUid());
            personInfoMap.put("LastChange", System.currentTimeMillis() / 1000);
            personInfoMap.put("PersonCode", String.valueOf(user.getUid()));
            personInfoMap.put("PersonName", user.getName());
            personInfoMap.put("Remarks", "");
            personInfoMap.put("TimeTemplateNum", 0);
            personInfoMap.put("TimeTemplateList", Lists.newArrayList());
            personInfoMap.put("IdentificationNum", 0);
            personInfoMap.put("IdentificationList", Lists.newArrayList());
            personInfoMap.put("PersonPIN", "123456");
            IasDeviceUser deviceUser = deviceUserService.queryByUid(user.getUid(), deviceId);
            if (StringUtils.isBlank(user.getFaceImg()) && (deviceUser == null || StringUtils.isBlank(deviceUser.getImageData()))) {
                personInfoMap.put("ImageNum", 0);
                personInfoMap.put("ImageList", Lists.newArrayList());
            } else {
                personInfoMap.put("ImageNum", 1);
                //组装人脸信息
                Map<String, Object> faceMap = new LinkedHashMap<>();
                List<IasFace> faceList = faceService.queryByUserId(user.getId());
                if (CollectionUtils.isEmpty(faceList)) {
                    String base64Img = deviceUser.getImageData();
                    if (base64Img == null) {
                        log.error("[base64Img] is null,[{}]", user.getUid());
                    }
                    faceMap.put("FaceID", deviceUser.getId());
                    faceMap.put("Name", user.getName());
                    faceMap.put("Size", base64Img.replaceAll(" ", "").length());
                    faceMap.put("Data", base64Img);
                } else {
                    IasFace face = faceList.get(0);
                    userFaceIdMap.put(user.getId(), face.getId());
                    if (face == null) {
                        log.error("Cannot find any face info with the userId:{}", user.getId());
                        return;
                    }
                    faceMap.put("FaceID", face.getId());
                    faceMap.put("Name", face.getName());
                    try {
                        String base64Img = imageUtils.remoteImageToBase64(face.getImagePath());
                        faceMap.put("Size", base64Img.replaceAll(" ", "").length());
                        faceMap.put("Data", base64Img);
                    } catch (IOException e) {
                        log.error("图片转换Base64异常", e.getMessage());
                        return;
                    }
                }

                List<Map> imageLst = Lists.newArrayList();
                imageLst.add(faceMap);
                personInfoMap.put("ImageList", imageLst);
            }
            personInfoMap.put("FingerprintNum", 0);
            personInfoMap.put("FingerprintList", Lists.newArrayList());
            personInfoList.add(personInfoMap);
        });

        requestMap.put("PersonInfoList", personInfoList);
        UnvDevice device = unvDeviceService.getById(deviceId);
        String url = "http://" + device.getIp();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "*/*");
        headers.setConnection("keep-alive");
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        JSONObject obj = new JSONObject(requestMap);
        HttpEntity request = new HttpEntity(obj.toString(), headers);
        //默认人员库 3-默认员工库
        ResponseEntity<String> responseEntity = restTemplateUtils.post(url + UnvRequestURI.PEOPLE_LIBRARIES_ADD.getUri() + "3/People",
                request, String.class);
        JSONObject response = (JSONObject) JSONObject.parseObject(responseEntity.getBody()).get("Response");
        UnvPerson result = JSONObject.parseObject(String.valueOf(response.get("Data")), UnvPerson.class);
        try {
            IasFaceSyncRes syncRes = new IasFaceSyncRes();
            syncRes.setDeviceId(deviceId);
            syncRes.setUserFaceIdMap(userFaceIdMap);
            syncRes.setSyncTime(new Date());
            if (result == null) {
                syncRes.setUnvResp(JSONObject.toJSONString(response));
                syncRes.setSyncResult(0);
            } else {
                syncRes.setSyncResult(result.getNum() == userList.size() ? 1 : 0);
                syncRes.setUnvResp(JSONObject.toJSONString(result));
            }
            faceSyncResService.saveSyncRes(syncRes);
        } catch (Exception e) {
            log.error("同步下发记录保存失败,{}", response, e);
        }
        return result;
    }

    /**
     * 清空人员库信息
     *
     * @param deviceId
     * @return
     */
    public JSONObject truncatePeopleLibraries(Integer deviceId) {
        UnvDevice device = unvDeviceService.getById(deviceId);
        if (device == null) {
            log.error("truncatePeopleLibraries 清空人员库失败,未找到设备信息{}", deviceId);
            return null;
        }
        String url = "http://" + device.getIp() + UnvRequestURI.PEOPLE_LIBRARIES_TRUNCATE.getUri() + "3/People";
        ResponseEntity<String> responseEntity = restTemplateUtils.delete(url, null, String.class);
        JSONObject response = (JSONObject) JSONObject.parseObject(responseEntity.getBody()).get("Response");
        log.info("truncatePeopleLibraries response:{}", response);
        return response;
    }

    /**
     * 远程开关门
     *
     * @param deviceCode
     * @param control
     * @param personId
     * @return
     */
    public JSONObject remoteControlGUI(String deviceCode, Integer control, Long personId, Integer haveCheckedIn) {
        Map<String, Object> requestMap = Maps.newLinkedHashMap();
        String duplicateCheckKey = deviceCode + personId;
        String checkTypeFlag = "CHECK_TYPE_" + deviceCode + personId;
        //重复打卡校验
        if (redisUtils.getObject(duplicateCheckKey) != null) {
            requestMap.put("ResultCode", 0);
            control = 0;
        } else {
            redisUtils.set(duplicateCheckKey, 1, 1 * 60);
            redisUtils.deleteKey(checkTypeFlag);
            requestMap.put("ResultCode", control);
        }
        requestMap.put("PassTime", sdf.format(new Date()));
        requestMap.put("ResultCmd", 0);
        requestMap.put("CodeStatus", 1);
        requestMap.put("ResultColor", 1);
        // 上下班打卡校验
        String checkKey = CommonConstant.REDIS_CHECK_IN_OUT_KEY + deviceCode + personId;
        if (control == 1) {
            if (redisUtils.getObject(checkKey) == null) {
                redisUtils.set(checkKey, 2, 8 * 60 * 60);
                requestMap.put("ResultMsg", "上班打卡成功");
            } else {
                Integer checkVal = Integer.valueOf(redisUtils.getObject(checkKey));
                if (checkVal % 2 == 0) {
                    redisUtils.set(checkKey, 1, 30);
                    requestMap.put("ResultMsg", "下班打卡成功");
                } else {
                    redisUtils.set(checkKey, 2, 8 * 60 * 60);
                    requestMap.put("ResultMsg", "上班打卡成功");
                }
            }
        } else if (control == 0 && haveCheckedIn == 0) {
            requestMap.put("ResultMsg", "请先完成上班打卡");
        } else if (control == 0 && redisUtils.getObject(duplicateCheckKey) != null) {
            requestMap.put("ResultMsg", "重复打卡");
            redisUtils.set(checkTypeFlag, 1, 60);
        } else {
            requestMap.put("ResultMsg", "身份识别失败");
        }
        requestMap.put("AudioEnable", 0);
        requestMap.put("AudioIndex", 1);
        requestMap.put("ShowInfoNum", 2);
        List<Map<String, String>> infoList = Lists.newArrayList();
        Map<String, String> kvMap = Maps.newLinkedHashMap();
        String userName = "";
        IasUser user = userService.queryByUserOrPersonId(personId);
        if (user == null) {
            userName = "未记录";
        } else {
            userName = user.getName();
        }
        kvMap.put("Key", "姓名:");
        kvMap.put("Value", userName);
        infoList.add(kvMap);
        Map<String, String> kvMap2 = Maps.newLinkedHashMap();
        if (control == 1) {
            kvMap2.put("Key", "欢迎:");
            kvMap2.put("Value", "你已成功打卡");
        } else if (control == 0 && haveCheckedIn == 0) {
            kvMap2.put("Key", "请先完成上班打卡");
            kvMap2.put("Value", "");
        } else if (control == 0) {
            kvMap2.put("Key", "3分钟内重复打卡");
            kvMap2.put("Value", "");
        } else {
            kvMap2.put("Key", "识别失败");
            kvMap2.put("Value", "");
        }

        infoList.add(kvMap2);
        requestMap.put("ShowInfoList", infoList);
        requestMap.put("ImageEnable", 0);
        requestMap.put("ImageLen", 0);
        requestMap.put("ImageData", "");

        UnvDevice device = unvDeviceService.lambdaQuery().eq(UnvDevice::getSerialNumber, deviceCode).one();
        String url = "http://" + device.getIp() + UnvRequestURI.GUISHOWINFO_EX.getUri();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", "*/*");
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.setConnection("keep-alive");
        JSONObject obj = new JSONObject(requestMap);
        log.info("[remoteControlGUI] request:{}", obj);
        HttpEntity request = new HttpEntity(obj.toString(), headers);
        ResponseEntity<String> responseEntity = restTemplateUtils.put(url, request, String.class, requestMap);
        JSONObject response = (JSONObject) JSONObject.parseObject(responseEntity.getBody()).get("Response");
        log.info("[remoteControlGUI] response:{}", response);
        return response;
    }
}
